#include "cxcamerainfo.h"
#include <stdio.h>

dc1394_t                               *CxCameraInfo::s_dc1394;
size_t                                  CxCameraInfo::s_ref;
CxCameraInfo::_CameraInfos              CxCameraInfo::s_cameras;

CxCameraInfo::CxCameraInfo(QObject *parent) :
    QObject(parent)
{
    Init();
    ++s_ref;
}

CxCameraInfo::~CxCameraInfo()
{
    --s_ref;
    Release();
}

_CxResult       CxCameraInfo::Init()
{
    if(s_ref!=0)
        return CX_OK;

    /*  Init dc1394 */
    s_dc1394    =   dc1394_new();
    if(s_dc1394 == NULL)
        return CX_INIT_1394_FAILED;

    /*  List camera */
    dc1394error_t               error;
    dc1394camera_list_t         *cameralist;

    error   =  dc1394_camera_enumerate(s_dc1394,&cameralist);
    printError(error);

    for(int i=0;i<cameralist->num;++i)
    {
        CameraInfo          tmpinfo;
        tmpinfo.id          =   cameralist->ids[i];
        _CxResult  result   =   getCameraInfo(cameralist->ids[i],&tmpinfo);
        if(result!=CX_OK)
            return result;

        s_cameras.push_back(tmpinfo);
    }

    dc1394_camera_free_list(cameralist);
    return  CX_OK;
}


_CxResult       CxCameraInfo::Release()
{
    if(s_ref!=0)
        return CX_OK;

    dc1394_free(s_dc1394);
    s_dc1394    =   NULL;
    s_cameras.clear();
}


_CxResult       CxCameraInfo::getCameraInfo(dc1394camera_id_t id,CameraInfo *info)
{
    dc1394camera_t  *camera;
    dc1394error_t   error;

    /*  Init camera */
    camera  =   dc1394_camera_new(s_dc1394,id.guid);

    if(camera   ==  NULL)
        return  CX_INIT_CAMERA_FAILED;

    info->vender  =   QString(QString(camera->vendor)+QString(camera->model));

    error   =  dc1394_video_get_operation_mode(camera,&info->operationmode);
    printError(error);


    dc1394_video_get_supported_modes(camera,&info->modes);
    printError(error);

    for(int i=0;i<info->modes.num;++i)
    {
        if(info->modes.modes[i] >=  DC1394_VIDEO_MODE_FORMAT7_0)
            continue    ;

        dc1394framerates_t  rates;
        error   =   dc1394_video_get_supported_framerates(camera,info->modes.modes[i],&rates);
        printError(error);

        info->framerates.insert(info->modes.modes[i],rates);
    }

    dc1394_camera_free(camera);
    return CX_OK;
}

void            CxCameraInfo::printInfo(int   fd)
{
     char       buffer[BUFSIZ];
     FILE *fp  =  fdopen(fd,"w");

     if(fp  ==  NULL)
         return ;

     sprintf(buffer,"Camera number :    %d\n",s_cameras.size());
     fputs(buffer,fp);

     for(int i=0;i<s_cameras.size();++i)
     {
        sprintf(buffer,"Camera %d :\n\tVender:\t%s\n\tOperation mode:\t%s\n",i,
                s_cameras[i].vender.toStdString().c_str(),
                ((s_cameras[i].operationmode == DC1394_OPERATION_MODE_1394B)?"1394B":"1394A"));
        fputs(buffer,fp);

        fputs("\tSupport Mode:\n",fp);
        for(int j=0;j<s_cameras[i].modes.num;++j)
        {
            sprintf(buffer,"\t\t%s\n",formatModes(s_cameras[i].modes.modes[j]));
            fputs(buffer,fp);
        }
     }
}

bool            CxCameraInfo::haveMode(int device,dc1394video_mode_t  mode)
{
    if(device > s_cameras.size())
        return false;
    for(int i=0;i < s_cameras[device].modes.num;++i)
    {
        if(mode==s_cameras[device].modes.modes[i])
            return true;
    }
    return false;
}
bool            CxCameraInfo::haveRate(int device,dc1394video_mode_t mode,dc1394framerate_t rate)
{
    if(device > s_cameras.size())
        return false;

    if((s_cameras[device].framerates.find(mode))
            ==
            s_cameras[device].framerates.end())
        return  false;

    for(int i=0;i<s_cameras[device].framerates[mode].num;++i)
    {
        if(rate==s_cameras[device].framerates[mode].framerates[i])
            return true;
    }
    return false;
}

dc1394camera_t *CxCameraInfo::newCamera(int   device,  dc1394video_mode_t    mode,   dc1394framerate_t rate)
{
    if(device > s_cameras.size())
        return NULL;

    dc1394camera_t  *camera;
    dc1394error_t   error;

    dc1394video_mode_t _mode;
    dc1394framerate_t  _rate;

    /*  Select default video mode if mode is not support */
    if(!haveMode(device,mode))
        _mode=s_cameras[device].modes.modes[0];
    else
        _mode=mode;

    /*  Select default video rate if rate is not support */
    if(!haveRate(device,_mode,rate))
        _rate=s_cameras[device].framerates[_mode].framerates[s_cameras[device].framerates[_mode].num-1];
    else
        _rate=rate;

    /*  Create new Camera   */
    camera   =   dc1394_camera_new(s_dc1394,s_cameras[device].id.guid);

    if(camera   ==  NULL)
        return NULL;

    error   =   dc1394_video_set_transmission(camera,DC1394_OFF);
    printError(error);

    error   =   dc1394_video_set_operation_mode(camera,DC1394_OPERATION_MODE_1394B);
    printError(error);

    error   =   dc1394_video_set_iso_speed(camera,DC1394_ISO_SPEED_800);
    printError(error);

    error   =   dc1394_video_set_mode(camera,_mode);
    printError(error);

    error   =   dc1394_video_set_framerate(camera,_rate);
    printError(error);

    return camera;
}

inline  const   QString                 &CxCameraInfo::getcameraVender(int  device)
{
    if(device > s_cameras.size())
        return QString("");

    return  s_cameras[device].vender;

}

inline  const   dc1394video_modes_t     &CxCameraInfo::getsupportMode(int   device)
{
    static  dc1394video_modes_t mode;
    if(device > s_cameras.size())
        return mode;

    return  s_cameras[device].modes;
}

inline  const   dc1394framerates_t      &CxCameraInfo::getsupportRate(int device,dc1394video_mode_t  mode)
{
    static  dc1394framerates_t  rate;
    if(device > s_cameras.size())
        return rate;

    return  s_cameras[device].framerates[mode];
}
